package com.xx.landing;

import com.xx.hdfs.HdfsDemo;
import com.xx.hdfsFx.promptStage.ErrorPrompt;
import javafx.animation.ParallelTransition;
import javafx.animation.RotateTransition;
import javafx.animation.ScaleTransition;
import javafx.animation.SequentialTransition;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;

import javax.rmi.CORBA.Util;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static com.xx.util.Util.getResourceUrl;

public class Landing {
    private double offsetX;
    private double offsetY;
    private Stage app;
    private boolean flipping;
    private AnchorPane loadingPane;
    private AnchorPane enrollPane;
    private Map<String, Map> users;
    private Runnable run;
    private Map nowMap;
    private FileSystem fs;

    public Map getNowMap() {
        return nowMap;
    }

    public void setRun(Runnable run) {
        this.run = run;
    }

    public Landing(Stage app) {
        this.app = app;
        loading();
        DropShadow shadow = new DropShadow(8, new Color(0.0, 0.0, 0.0, 0.69));
        loadingPane = loadingPane();
        loadingPane.setEffect(shadow);
        enrollPane = enrollPane();
        enrollPane.setEffect(shadow);
        enrollPane.setVisible(false);
        StackPane sp = new StackPane();
        sp.setPadding(new Insets(10));
        sp.setBackground(Background.EMPTY);
        sp.getChildren().addAll(enrollPane, loadingPane);

        Scene scene = new Scene(sp, null);
        scene.getStylesheets().add(Objects.requireNonNull(
                Util.class.getResource("/css/landing.css")).toExternalForm());
        setDraggedScene(app, scene);
        app.initStyle(StageStyle.TRANSPARENT);
        app.setScene(scene);
        app.show();
    }

    private void loading() {
        try {
            ObjectInputStream inputStream =
                    new ObjectInputStream(Files.newInputStream(Paths.get("src/main/resources/saveAndLoading" + File.separator +
                            "accountInfo")));
            users = (HashMap<String, Map>) inputStream.readObject();
            inputStream.close();
        } catch (ClassNotFoundException | IOException e) {
            users = new HashMap<>();
            save();
        }
    }

    public void save() {
        try {
            ObjectOutputStream outputStream =
                    new ObjectOutputStream(Files.newOutputStream(Paths.get("src/main/resources/saveAndLoading" + File.separator + "accountInfo")));
            outputStream.writeObject(users);
            outputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private void flipAnim(Pane showPane, Pane hidePane, boolean dir) {
        if (flipping) {
            return;
        }
        flipping = true;
        //隐藏当前显示的页面
        Duration duration = Duration.millis(500);
        RotateTransition hideRt = new RotateTransition(duration, hidePane);
        hideRt.setAxis(Rotate.Y_AXIS);
        hideRt.setFromAngle(0);
        hideRt.setToAngle(dir ? 90 : -90);
        hideRt.setOnFinished(event -> {
            hidePane.setVisible(false);
            showPane.setVisible(true);
        });
        ScaleTransition hideSt = new ScaleTransition(duration, hidePane);
        hideSt.setFromX(1.0);
        hideSt.setToX(0.6);
        hideSt.setFromY(1.0);
        hideSt.setToY(0.6);

        ParallelTransition hideAnim = new ParallelTransition(hideRt, hideSt);

        //显示刚刚隐藏的页面
        RotateTransition showRt = new RotateTransition(duration, showPane);
        showRt.setAxis(Rotate.Y_AXIS);
        showRt.setFromAngle(dir ? -90 : 90);
        showRt.setToAngle(0);

        ScaleTransition showSt = new ScaleTransition(duration, showPane);
        showSt.setFromX(0.6);
        showSt.setToX(1.0);
        showSt.setFromY(0.6);
        showSt.setToY(1.0);

        ParallelTransition showAnim = new ParallelTransition(showRt, showSt);

        SequentialTransition st = new SequentialTransition(hideAnim, showAnim);
        st.setOnFinished(event -> flipping = false);
        st.play();
    }

    private AnchorPane enrollPane() {
        ImageView backGround = new ImageView(new Image(getResourceUrl("/texture/background0.png")));
        backGround.setPreserveRatio(true);
        backGround.setFitWidth(1000);
        AnchorPane root = new AnchorPane();
        root.getChildren().add(backGround);
        root.setPrefSize(backGround.getFitWidth(), backGround.getFitHeight());

        VBox v = new VBox(20);
        v.setAlignment(Pos.CENTER);
        v.setLayoutX(330);
        v.setLayoutY(100);

        Input accountInput = new Input(new ImageView(new Image(getResourceUrl("/texture/user.png"))),
                new ImageView(new Image(getResourceUrl("/texture/x.png"))));
        accountInput.setPromptText("输入账号(仅支持大小写字母和阿拉伯数字)");
        TextField accountTf = accountInput.textField;
        accountTf.setTextFormatter(new TextFormatter<>(e -> {
            if (e.getText().matches("[a-zA-Z0-9]*")) return e;
            return null;
        }));
        accountTf.textProperty().addListener((ob, ov, nv) -> accountInput.setRight(!users.containsKey(nv) && !nv.equals("")));

        Input passwordInput = new Input(new ImageView(new Image(getResourceUrl("/texture/password.png"))),
                new ImageView(new Image(getResourceUrl("/texture/x.png"))), new ImageView(new Image(getResourceUrl(
                "/texture/cantSee.png"))));
        passwordInput.setPromptText("输入密码(仅支持大小写字母和阿拉伯数字)");
        PasswordField passwordTF = passwordInput.passwordField;
        passwordTF.setTextFormatter(new TextFormatter<>(e -> {
            if (e.getText().matches("[a-zA-Z0-9]*"))
                return e;
            return null;
        }));
        passwordTF.textProperty().addListener((ob, ov, nv) -> passwordInput.setRight(!Objects.equals(nv, "")));
        passwordInput.textField.textProperty().addListener((ob, ov, nv) -> passwordInput.setRight(!Objects.equals(nv, "")));

        Input ipInput = new Input(new ImageView(new Image(getResourceUrl("/texture/IP.png"))),
                new ImageView(new Image(getResourceUrl("/texture/x.png"))));
        ipInput.setPromptText("输入IP网址");
        TextField ipTF = ipInput.textField;
        ipTF.textProperty().addListener((ob, ov, nv) -> {
            ipInput.setRight(!Objects.equals(nv, ""));
        });

        Input portInput = new Input(new ImageView(new Image(getResourceUrl("/texture/port.png"))),
                new ImageView(new Image(getResourceUrl("/texture/x.png"))));
        portInput.setPromptText("输入端口号(仅支持大小写字母和阿拉伯数字)");
        TextField portTF = portInput.textField;
        portTF.textProperty().addListener((ob, ov, nv) -> portInput.setRight(!Objects.equals(nv, "")));

        Input userInput = new Input(new ImageView(new Image(getResourceUrl("/texture/root"))),
                new ImageView(new Image(getResourceUrl("/texture/x.png"))));
        userInput.setPromptText("用户权限(仅支持大小写字母)");
        TextField nameTF = userInput.textField;
        nameTF.setTextFormatter(new TextFormatter<>(e -> {
            if (e.getText().matches("[a-zA-Z]*"))
                return e;
            return null;
        }));
        nameTF.textProperty().addListener((ob, ov, nv) -> userInput.setRight(!Objects.equals(nv, "")));

        Button save = new javafx.scene.control.Button("保存");
        save.setDisable(true);
        save.setOnAction(event -> {
            Map user = new HashMap();
            user.put("accountT", accountTf.getText().trim());
            user.put("password", passwordTF.getText().trim());
            user.put("ip", ipTF.getText().trim());
            user.put("port", portTF.getText().trim());
            user.put("name", nameTF.getText().trim());
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            user.put("time", dateFormat.format(System.currentTimeMillis()));
            users.put(accountTf.getText().trim(), user);
            save();
            save.setDisable(true);
        });
        root.getChildren().add(save);
        save.setTextFill(Color.SKYBLUE);
        AnchorPane.setBottomAnchor(save, 0.0);
        AnchorPane.setLeftAnchor(save, 0.0);

        Button test = new Button("测试链接");
        test.setOnAction(event -> {
            if (!accountInput.getRight()) {
                if (Objects.equals(accountTf.getText(), "")) getDialog("空账号", "请输入非空账号.",
                        new Image(getResourceUrl("/texture/nullUser.png")));
                else getDialog("账号已存在", "你输入的账号'" + accountTf.getText().trim() + "'已存在," +
                        "请重新输入账号.", new Image(getResourceUrl("/texture/nullUser.png")));
                return;
            }
            if (!passwordInput.getRight()) {
                getDialog("密码错误", "你输入的密码为空,请输入非空密码.", new Image(getResourceUrl("/texture/nullPassword.png")));
                return;
            }
            if (!ipInput.getRight() || !portInput.getRight() || !userInput.getRight()) {
                return;
            }
            LoadingButton.butLoading(test, () -> {
                save.setDisable(!testConnect(ipTF.getText().trim(), portTF.getText().trim(),
                        nameTF.getText().trim()));
                return true;
            });
        });
        root.getChildren().add(test);
        test.setTextFill(Color.SKYBLUE);
        AnchorPane.setBottomAnchor(test, 0.0);
        AnchorPane.setLeftAnchor(test, root.getPrefWidth() / 2 - 110);

        javafx.scene.control.Button quit = new javafx.scene.control.Button("退出");
        root.getChildren().add(quit);
        quit.setOnAction(event -> flipAnim(loadingPane, enrollPane, false));
        quit.setTextFill(Color.SKYBLUE);
        AnchorPane.setRightAnchor(quit, 0.0);
        AnchorPane.setBottomAnchor(quit, 0.0);

        javafx.scene.control.Button close = new javafx.scene.control.Button("X");
        root.getChildren().add(close);
        close.setTextFill(Color.SKYBLUE);
        close.setOnAction(event -> {
            app.close();
        });
        AnchorPane.setTopAnchor(close, 0.0);
        AnchorPane.setRightAnchor(close, 0.0);

        v.getChildren().addAll(accountInput.hb, passwordInput.hb, ipInput.hb, portInput.hb, userInput.hb);
        root.getChildren().add(v);

        return root;
    }

    private boolean testConnect(String ip, String port, String name) {
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://" + ip + ":" + port);
        System.setProperty("HADOOP_USER_NAME", name);
//        进行客户端身份认证

        try {
            fs = FileSystem.get(conf);
            HdfsDemo demo = new HdfsDemo(fs);
            boolean test = demo.test();
            Platform.runLater(() -> {
                if (test)
                    getDialog("链接正常", "链接成功", new Image(getResourceUrl("/texture/nullConnect.png")));
            });
            fs.close();
            return test;
        } catch (IOException e) {
            Platform.runLater(() -> getDialog("链接错误", "链接出现异常.", new Image(getResourceUrl("/texture/nullConnect.png"))));
            return false;
        } catch (RuntimeException e) {
            Platform.runLater(() -> getDialog("链接错误", "链接超时,请检查hadoop集群是否开启.", new Image(getResourceUrl("/texture/nullConnect.png"))));
            return false;
        }
    }

    private void getDialog(String header, String content, Image image) {

        ErrorPrompt errorPrompt = new ErrorPrompt(image, header, content);
        errorPrompt.addOwner(app);
        errorPrompt.showStage();
    }

    private AnchorPane loadingPane() {
        ImageView backGround = new ImageView(new Image(getResourceUrl("/texture/background.png")));
        backGround.setPreserveRatio(true);
        backGround.setFitWidth(1000);
        AnchorPane root = new AnchorPane();
        root.getChildren().add(backGround);
        root.setPrefSize(backGround.getFitWidth(), backGround.getFitHeight());

        VBox v = new VBox(20);
        v.setAlignment(Pos.CENTER);
        v.setLayoutX(330);
        v.setLayoutY(340);

        Input userInput = new Input(new ImageView(new Image(getResourceUrl("/texture/user.png"))),
                new ImageView(new Image(getResourceUrl("/texture/x.png"))));
        userInput.setPromptText("输入账号(仅支持大小写字母和阿拉伯数字)");
        TextField userTF = userInput.textField;
        userTF.textProperty().addListener((ob, ov, nv) -> userInput.setRight(users.containsKey(nv)));
        userTF.setTextFormatter(new TextFormatter<>(e -> {
            if (e.getText().matches("[a-zA-Z0-9]*"))
                return e;
            return null;
        }));

        Input passwordInput = new Input(new ImageView(new Image(getResourceUrl("/texture/password.png"))),
                new ImageView(new Image(getResourceUrl("/texture/x.png"))), new ImageView(new Image(getResourceUrl(
                "/texture/cantSee.png"))));
        passwordInput.setPromptText("输入密码(仅支持大小写字母和阿拉伯数字)");
        PasswordField passwordTF = passwordInput.passwordField;
        passwordTF.setTextFormatter(new TextFormatter<>(e -> {
            if (e.getText().matches("[a-zA-Z0-9]*"))
                return e;
            System.out.println(e);
            return null;
        }));

        v.getChildren().addAll(userInput.hb, passwordInput.hb);
        root.getChildren().add(v);

        Button test = new javafx.scene.control.Button("测试链接");
        root.getChildren().add(test);
        test.setTextFill(Color.SKYBLUE);
        test.setOnAction(event -> {
            if (!userInput.getRight()) {
                getDialog("账号不存在", "你输入的账号:'" + userTF.getText().trim() + "' 不存在,请检查后重试.", new Image(getResourceUrl(
                        "/texture/nullUser.png")));
                return;
            }
            Map map = users.get(userTF.getText().trim());
            if (!passwordTF.isVisible()) passwordTF.setText(passwordInput.textField.getText());
            passwordInput.setRight(map.get("password")
                    .equals(passwordTF.getText().trim()));
            if (passwordInput.getRight()) {
                LoadingButton.butLoading(test, () -> {
                    testConnect(map.get("ip").toString(), map.get("port").toString(),
                            map.get("name").toString());
                    return true;
                });
            } else {
                getDialog("密码错误", "账号" + userTF.getText().trim() + " 的密码输入错误,请重试.",
                        new Image(getResourceUrl("/texture/nullPassword.png")));
            }
            ;
        });
        AnchorPane.setBottomAnchor(test, 0.0);
        AnchorPane.setLeftAnchor(test, 0.0);

        Button enroll = new Button("注册账号");
        enroll.setOnAction(event -> flipAnim(enrollPane, loadingPane, true));
        root.getChildren().add(enroll);
        AnchorPane.setBottomAnchor(enroll, 0.0);
        AnchorPane.setRightAnchor(enroll, 0.0);

        Button landing = new Button("登陆");
        root.getChildren().add(landing);
        landing.setOnAction(event -> {
            if (!userInput.getRight()) {
                getDialog("账号不存在", "你输入的账号:'" + userTF.getText().trim() + "' 不存在,请检查后重试.",
                        new Image(getResourceUrl("/texture/nullUser.png")));
                return;
            }
            nowMap = users.get(userTF.getText().trim());
            if (!passwordTF.isVisible()) passwordTF.setText(passwordInput.textField.getText());
            passwordInput.setRight(nowMap.get("password").equals(passwordTF.getText().trim()));
            if (!passwordInput.getRight())
                getDialog("密码错误", "账号" + userTF.getText().trim() + " " +
                        "的密码输入错误,请重试.", new Image(getResourceUrl("/texture/nullPassword.png")));
            if (userInput.getRight() && passwordInput.getRight()) {
                LoadingButton.butLoading(test, () -> {
                    if (testConnect(nowMap.get("ip").toString(), nowMap.get("port").toString(), nowMap.get(
                            "name").toString())) Platform.runLater(run);
                    return true;
                });
            }
        });
        AnchorPane.setBottomAnchor(landing, 0.0);
        AnchorPane.setLeftAnchor(landing, (root.getPrefWidth()) / 2 - 60);

        Button close = new Button("X");
        root.getChildren().add(close);
        close.setTextFill(Color.SKYBLUE);
        close.setOnAction(event -> {
            app.close();
            if (fs != null)
                try {
                    fs.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
        });
        AnchorPane.setTopAnchor(close, 0.0);
        AnchorPane.setRightAnchor(close, 0.0);

        return root;
    }

    private void setDraggedScene(Stage stage, Scene scene) {
        scene.setOnMousePressed(event -> {
            offsetX = event.getSceneX();
            offsetY = event.getSceneY();
        });
        scene.setOnMouseDragged(event -> {
            stage.setX(event.getScreenX() - offsetX);
            stage.setY(event.getScreenY() - offsetY);
        });
    }
}
